#ifndef _COMUTILIY_SCHANNEL_HPP_
#define _COMUTILIY_SCHANNEL_HPP_

#include <comutiliy/asynio.h>

class SChannel			
{
public:
	SChannel(void) {

	}
	virtual ~SChannel(void) {

	}

	std_method_impl CreateSChannel(IBase *pRot) {

		HRESULT hr = S_OK;
		rc_assert(pRot != NULL, E_FAIL)

		hr = pRot->QueryInterface(IID_IComRunningObjectTable, (void**)&m_pRot);
		rc_assert(hr == S_OK, E_FAIL)

		hr = m_pRot->GetObject(CLSID_IAsynFrame, IID_IAsynFrame, (IBase**)&m_pIAsynFrame);
		rc_assert(hr == S_OK, E_FAIL)

		hr = m_pIAsynFrame->CreateIo(io_tcplisten_socket, (IBase**)&m_pIListen);
		rc_assert(hr == S_OK, E_FAIL)

		return S_OK;
	}
	std_method_impl OpenCChannel() {

		HRESULT hr = S_OK;

		hr = m_pIListen->CreateSock();
		rc_assert(hr == S_OK, E_FAIL)

		hr = m_pIListen->OpenIo();
		rc_assert(hr == S_OK, E_FAIL)

		hr = m_pIListen->BindIo();
		rc_assert(hr == S_OK, E_FAIL)

		return hr;
	}
	std_method_impl BindEvent(IBase* pBase) {

		return m_pIListen->BindAccept(pBase);
	}
	std_method_impl UnBindEvent() {

		return m_pIListen->UnBindAccpet();
	}
	std_method_impl ListenChannel(LPCSTR addr, int len) {

		rc_assert(addr != NULL, E_FAIL)
		rc_assert(len != 0, E_FAIL)

		HRESULT hr = S_OK;

		CharArrayPtr item;
		item.dispose();
		item = ALLOC_NEW char[BROKER_ADDR_MAXLEN + 1]();
		rc_assert(item.m_p != NULL, E_FAIL)
		s_strcpy(item, BROKER_ADDR_MAXLEN, addr);

		char* port = NULL;
		char* ip = NULL;

		ip = s_strtok(item, ":", &port);
		rc_assert(ip != NULL, E_FAIL)
		rc_assert(port != NULL, E_FAIL)

		hr = m_pIListen->Listen(ip, atoi(port));
		rc_assert(hr == S_OK, E_FAIL)

		return hr;
	}
	std_method_impl AcceptCChannel() {

		HRESULT hr = S_OK;
		_lComPtr<ITcpSocket> pSocket;

		hr = m_pIAsynFrame->CreateIo(io_tcp_socket, (IBase**)&pSocket);
		rc_assert(hr == S_OK, E_FAIL)

		hr = pSocket->OpenIo();
		rc_assert(hr == S_OK, E_FAIL)

		pSocket->AddRef(); // + 1

		hr = m_pIListen->Accept(pSocket);
		rc_assert(hr == S_OK, E_FAIL)

		return S_OK;
	}
	std_method_impl CloseChannel() {

		HRESULT hr = S_OK;

		hr = m_pIListen->CloseIo(CLOSE_BOTH_IO);
		rc_assert(hr == S_OK, E_FAIL)

		hr = m_pIListen->CloseSock();
		rc_assert(hr == S_OK, E_FAIL)

		hr = m_pIListen->UnBindAccpet();
		rc_assert(hr == S_OK, E_FAIL)

		m_pIListen.dispose();

		m_pIAsynFrame.dispose();

		m_pRot.dispose();

		return S_OK;
	}
	std_method_impl IsListenChannel() {
		return m_pIListen->IsOpen();
	}

	std_method_impl GetObject(IBase *pIBase, TcpSocketPtr& pSocket, OperationPtr& pOperation)
	{
		HRESULT hr = S_OK;

		hr = pIBase->QueryInterface(IID_IOperation, (void**)&pOperation);
		rc_assert(hr == S_OK, E_FAIL)

		hr = pOperation->QueryIBaseIID(IID_ITcpSocket, (void**)&pSocket);
		rc_assert(hr == S_OK, E_FAIL)

		return hr;
	}

	std_method_impl Send(const TcpSocketPtr& pSocket, const OperationPtr& pOperation,unsigned int len, event_id eventid)
	{
		HRESULT hr = S_OK;

		hr = pOperation->SetExpect(len);
		rc_assert(hr == S_OK, E_FAIL)

		hr = pSocket->WriteIo(pOperation, eventid);
		rc_assert(hr == S_OK, E_FAIL)

		return hr;
	}

	std_method_impl Recv(const TcpSocketPtr& pSocket, const OperationPtr& pOperation, unsigned int len, event_id eventid)
	{
		HRESULT hr = S_OK;

		hr = pOperation->SetExpect(len);
		rc_assert(hr == S_OK, E_FAIL)

		hr = pSocket->ReadIo(pOperation, eventid);
		rc_assert(hr == S_OK, E_FAIL)

		return hr;
	}

protected:
	_lComPtr<IComRotMessage>			m_pRot;
	AsynFramePtr						m_pIAsynFrame;
	TcpListenPtr						m_pIListen;

};

#endif

